﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FullThrustLogic.Helper;
using FullThrustLogic.ShipComponent;
using FullThrustLogic.ShipComponent.Weapon;

namespace FullThrustLogic.Core.GameState
{
    public class AttackOrderState : iGameState
    {
        private GameContext _gameContext;
        private TypeOfPlayer _controllingPlayer;
        private Ship _targetingShip;


        public event GameContext.GameStateChangedHandler OnGameStateChanged;

        
        public TypeOfPlayer ControllingPlayer
        {
            get { return _controllingPlayer; }
        }
       
        public void AdvanceState()
        {
            foreach(Player player in _gameContext.Players)
            {
                foreach(Ship ship in player.Ships)
                {
                    ship.AvailableToFire = true;
                }
            }

            if(OnGameStateChanged!=null)
            {
                OnGameStateChanged(this, new EventArgs());
            }
        }

        public AttackOrderState(GameContext gameContext)
        {
            _gameContext = gameContext;

            RollForInitiative(_gameContext.Players);

        }

        private void RollForInitiative(List<Player> players)
        {
            int highestDiceRoll = 0;
            List<Player> tiedPlayers = new List<Player>();

            foreach (Player player in players)
            {
                int currentDiceRoll =  DiceHelper.RollDice();

                if(tiedPlayers.Count ==0 || currentDiceRoll == highestDiceRoll)
                {
                    tiedPlayers.Add(player);
                }
            }

            if(tiedPlayers.Count == 1)
            {
                _controllingPlayer = tiedPlayers[0].PlayerType;
            }
            else
            {
                RollForInitiative(tiedPlayers);
            }
        }

        public void SetTargetingShip(Ship ship)
        {
            if (ship.Enabled)
            {
                if (_gameContext.Players[(int) _controllingPlayer].Ships.Contains(ship))
                {
                    if (_targetingShip != null&&_targetingShip!= ship)
                    {
                        foreach (FireControlSystem fcs in _targetingShip.FireControlSystems)
                        {
                            fcs.AttackOrders.Clear();
                        }
                    }

                    _targetingShip = ship;
                }
            }
        }

        public void ExcuteShipsAttacks()
        {
            foreach(FireControlSystem fcs in _targetingShip.FireControlSystems)
            {
                foreach(AttackOrder attackOrder in fcs.AttackOrders)
                {
                    attackOrder.ApplyOrder(_targetingShip, fcs.TargetShip);
                }
            }

            _targetingShip.AvailableToFire = false;

            DetermineNextPlayer();

        }

        private void DetermineNextPlayer()
        {
            int nextPlayer = ((int) (_controllingPlayer)) + 1%_gameContext.Players.Count;
            _controllingPlayer = (TypeOfPlayer) nextPlayer;

            bool hasNoShips = true;

            foreach (Ship ship in _gameContext.Players[(int)_controllingPlayer].Ships)
            {
                if (ship.Enabled && ship.AvailableToFire)
                {
                    hasNoShips = false;
                }
            }

            if(hasNoShips)
            {
                bool noShipsLeft = true;

                foreach(Player player in _gameContext.Players)
                {
                    foreach(Ship ship in player.Ships)
                    {
                        if(ship.Enabled && ship.AvailableToFire)
                        {
                            noShipsLeft = false;
                        }
                    }
                }

                if(noShipsLeft)
                {
                    AdvanceState();
                }
                else
                {
                    DetermineNextPlayer();
                }
            }
        }

        public FireControlSystem RequestFireControlSystem()
        {
            foreach(FireControlSystem fcs in _targetingShip.FireControlSystems)
            {
                if(fcs.TargetShip == null && fcs.Enabled)
                {
                    return fcs;
                }
            }

            return null;
        }

        public List<Ship> GetShipsInRange(Ship targetingShip, iWeapon targetingWeapon)
        {
            List<Ship> shipsInRange = new List<Ship>();

            if (targetingWeapon.Enabled && targetingShip.Weapons.Contains(targetingWeapon))
            {
                double distance = 0;
               
                foreach (Player player in _gameContext.Players)
                {
                    if (player.PlayerType != targetingShip.OwnerPlayer.PlayerType)
                    {
                        foreach (Ship ship in player.Ships)
                        {
                            distance = XYHelper.DistanceBetweenPoints(targetingShip.PositionX, targetingShip.PositionY, ship.PositionX, ship.PositionY);

                            if (distance <= targetingWeapon.Range)
                            {
                                if (targetingWeapon.InArc(targetingShip, ship))
                                {
                                    shipsInRange.Add(ship);
                                }
                            }
                        }
                    }
                }
            }

            return shipsInRange;
        }

        public bool IsShipInRange(Ship targetingShip, Ship targetedShip, iWeapon targetingWeapon)
        {
            double distance = XYHelper.DistanceBetweenPoints(targetingShip.PositionX, targetingShip.PositionY, targetedShip.PositionX, targetedShip.PositionY);

            if (distance <= targetingWeapon.Range)
            {
                if (targetingWeapon.InArc(targetingShip, targetedShip))
                {
                    return true;
                }
            }

            return false;
        }


        public void GetNextPlayer()
        {
            int numberOfPlayersChecked = 0;
            int nextPlayer = (int) ControllingPlayer;
            bool stillShipsInPlay = false;

            while (numberOfPlayersChecked < _gameContext.Players.Count)
            {
                nextPlayer = (nextPlayer + 1)%_gameContext.Players.Count;

                if (DoesPlayerHaveShipsAvailable(nextPlayer))
                {
                    _controllingPlayer = (TypeOfPlayer) nextPlayer;
                    stillShipsInPlay = true;
                    break;
                }

                numberOfPlayersChecked++;
            }

            if(!stillShipsInPlay)
            {
                _gameContext.CurrentState.AdvanceState();
            }

        }

        private bool DoesPlayerHaveShipsAvailable(int player)
        {
            foreach(Ship ship in _gameContext.Players[player].AvailableToAttackShips)
            {
                if(ship.AvailableToFire)
                {
                    return true;
                }
            }

            return false;
        }
    }
}
